feat: add kotlin-example module using android-sdk-framework directly#254
feat: add kotlin-example module using android-sdk-framework directly#254typotter wants to merge 1 commit into
Conversation
New :kotlin-example Android app demonstrating direct use of :android-sdk-framework (not :eppo). - KotlinxConfigurationParser implements ConfigurationParser<JsonElement> using kotlinx.serialization for parseJsonValue; delegates parseFlagConfig and parseBanditParams to JacksonConfigurationParser (framework DTOs have hand-rolled Jackson deserializers in sdk-common-jvm) - OkHttpEppoClient from sdk-common-jvm:4.0.0-SNAPSHOT for HTTP (OkHttp 4.x) - BaseAndroidClient.Builder wired in EppoApplication.onCreate() - MainActivity shows flag assignment result via getStringAssignment() - Make CachingConfigurationStore.seedCache() public (was package-private, inaccessible from BaseAndroidClient in a different package)
aarsilv
left a comment
There was a problem hiding this comment.
Nice work proving this out in an example!
| * format. Only [parseJsonValue] uses kotlinx.serialization, since that is the method that | ||
| * returns the user-facing [JsonElement] type. | ||
| */ | ||
| class KotlinxConfigurationParser : ConfigurationParser<JsonElement> { |
There was a problem hiding this comment.
Pull request overview
Adds a new Kotlin sample Android app module (:kotlin-example) that demonstrates using :android-sdk-framework directly (w/ kotlinx.serialization for JSON flag values and OkHttp 4.x for HTTP), and adjusts framework visibility to support this usage.
Changes:
- Add new
:kotlin-exampleAndroid application module (Kotlin + kotlinx.serialization + OkHttp). - Wire
BaseAndroidClient.BuilderusingKotlinxConfigurationParserandOkHttpEppoClient. - Make
CachingConfigurationStore.seedCache()public to allow cross-package use fromBaseAndroidClient.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
settings.gradle |
Includes the new :kotlin-example module in the build. |
build.gradle |
Adds Kotlin Android + Kotlin serialization plugins at the root. |
android-sdk-framework/src/main/java/cloud/eppo/android/framework/storage/CachingConfigurationStore.java |
Makes seedCache() public for use outside the storage package. |
kotlin-example/build.gradle |
Defines the new app module, dependencies (OkHttp, kotlinx.serialization), and BuildConfig API key wiring. |
kotlin-example/src/main/AndroidManifest.xml |
Declares the sample app, EppoApplication, and launcher activity. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/EppoApplication.kt |
Initializes BaseAndroidClient asynchronously using the framework + OkHttp client. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/MainActivity.kt |
Displays a sample string assignment result. |
kotlin-example/src/main/kotlin/cloud/eppo/kotlinexample/KotlinxConfigurationParser.kt |
Implements ConfigurationParser<JsonElement> using kotlinx.serialization for JSON values. |
kotlin-example/src/main/res/layout/activity_main.xml |
Basic UI for status + assignment display. |
kotlin-example/src/main/res/values/colors.xml |
Sample theme colors. |
kotlin-example/src/main/res/values/strings.xml |
App strings for UI text. |
kotlin-example/src/main/res/values/themes.xml |
MaterialComponents theme for the sample app. |
kotlin-example/proguard-rules.pro |
Placeholder ProGuard config for the module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def localProperties = new Properties() | ||
| def localPropertiesFile = rootProject.file('local.properties') | ||
| if (localPropertiesFile.exists()) { | ||
| localProperties.load(new FileInputStream(localPropertiesFile)) |
There was a problem hiding this comment.
The Gradle script loads local.properties via new FileInputStream(...) but never closes the stream. In long-lived Gradle daemons this can leak file descriptors. Use localPropertiesFile.withInputStream { localProperties.load(it) } (or a try-with-resources equivalent) to ensure the stream is closed.
| localProperties.load(new FileInputStream(localPropertiesFile)) | |
| localPropertiesFile.withInputStream { localProperties.load(it) } |
| try { | ||
| json.parseToJsonElement(jsonValue) | ||
| } catch (e: Exception) { | ||
| throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e) |
There was a problem hiding this comment.
The thrown ConfigurationParseException message includes the full jsonValue string. This can unintentionally leak sensitive flag payloads into logs/crash reports and can also be very large. Prefer omitting the raw value (or logging a truncated/length-only version) and rely on the cause exception for debugging details.
| throw ConfigurationParseException("Failed to parse JSON value: $jsonValue", e) | |
| throw ConfigurationParseException( | |
| "Failed to parse JSON value (length=${jsonValue.length})", | |
| e, | |
| ) |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Warning Review limit reached
More reviews will be available in 59 minutes and 38 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
New
:kotlin-exampleAndroid application module demonstrating how to use:android-sdk-frameworkdirectly (without going through:eppo). Written in Kotlin, uses kotlinx.serialization for JSON flag values and OkHttp 4.x for HTTP.Stacked on
snapshot/typo/apr-17.What's in this PR
New module:
:kotlin-exampleKotlinxConfigurationParserConfigurationParser<JsonElement>—parseJsonValueuses kotlinx.serialization;parseFlagConfig/parseBanditParamsdelegated toJacksonConfigurationParser(framework DTOs have hand-rolled Jackson deserializers)EppoApplicationBaseAndroidClient.BuilderwithKotlinxConfigurationParser+OkHttpEppoClientinApplication.onCreate()MainActivitygetStringAssignment()Changed:
CachingConfigurationStore.seedCache()visibilityMade
public(was package-private).BaseAndroidClientandCachingConfigurationStoreare in different packages so package-private was inaccessible.Dependency note
Uses
sdk-common-jvm:4.0.0-SNAPSHOTnot3.13.1. The old3.13.1monolithic jar bundleseppo-sdk-frameworkclasses and produces duplicate class errors when combined witheppo-sdk-framework:0.1.0-SNAPSHOTfrom:android-sdk-framework.Resolves #253